package com.kornero.auto.view;

import com.kornero.auto.entities.Car;
import com.kornero.auto.util.data.DataSource;
import com.kornero.auto.util.view.LayoutManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.Collection;

public class TablePanelImpl extends Composite implements ITablePanel {

    private static final Logger logger = LoggerFactory.getLogger(TablePanelImpl.class);
    private static final String[] columns = new String[]{"Model", "Price", "Year", "EngineKPP", "Type", "Distance",
            "Photo", "Carcase", "Color", "City", "Date"};

    private static final String LINK_KEY = "link";
    private static final String CAR_KEY = "car";
    private static final int linkColumn = 0;
    private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");

    private Table table;

    public TablePanelImpl(Composite parent) {
        this(parent, SWT.BORDER);
    }

    public TablePanelImpl(Composite parent, int style) {
        super(parent, style);
        this.constructUI();
    }

    private void constructUI() {
        this.setLayout(LayoutManager.getGridLayout());
        this.setLayoutData(LayoutManager.getLayoutDataFillAll());

        this.table = createTable(this);

        this.pack();
    }

    @Override
    public void setTable(final Collection<Car> cars) {

        // Отключаем перерисовку, пока будем добавлять новые элементы.
        table.setRedraw(false);

        // Удаляем старые атрибуты.
        removeAll();
        System.gc();

        for (final Car car : DataSource.sortCarsByDate(cars)) {
            addCar(car);
        }

        // Включаем перерисовку после добавления новых элементов.
        table.setRedraw(true);
    }

    @Override
    public void addCar(final Car car) {
        logger.debug("addCar(): {}", car);
        final TableItem item = addElement(car);
        final String url = car.getLink().toString();
        final Link link = new Link(table, SWT.WRAP);
        link.setText("<a href=\"" + url + "\">" + item.getText(linkColumn) + "</a>");
        link.setBackground(item.getBackground());
        link.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                org.eclipse.swt.program.Program.launch(url);
                item.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
                link.setBackground(item.getBackground());
                car.setChecked(true);
            }
        });

        //set hyperlinks in column "linkColumn".
        createTableEditor().setEditor(link, item, linkColumn);
        item.setData(LINK_KEY, link);
    }

    @Override
    public void removeCar(final Car car) {
        logger.debug("removeCar(): car = {}", car);
        final TableItem[] items = table.getItems();
        for (int i = 0, itemsLength = items.length; i < itemsLength; i++) {
            TableItem tableItem = items[i];
            if (tableItem.getData(CAR_KEY).equals(car)) {
                createTableEditor().setEditor(null, tableItem, linkColumn);
                ((Link) tableItem.getData(LINK_KEY)).dispose();

                table.clear(i);
                table.remove(i);
                tableItem.dispose();
                return;
            }
        }
        logger.warn("removeCar(): Car not found!");
    }

    @Override
    public void removeAll() {
        logger.debug("removeAll(): Total object for removing = {}", this.table.getItemCount());
        for (final TableItem tableItem : table.getItems()) {
            ((Link) tableItem.getData(LINK_KEY)).dispose();
            createTableEditor().setEditor(null, tableItem, linkColumn);
        }
        table.clearAll();
        table.removeAll();
    }

    private TableItem addElement(final Car car) {
        final String[] attributes = getAttributesFromCar(car);
        if (attributes.length != columns.length) {
            throw new RuntimeException();
        }
        final TableItem item = new TableItem(table, SWT.NONE);
        for (int i = 0; i < attributes.length; i++) {
            item.setText(i, attributes[i]);
        }
        if (car.isChecked()) {
            item.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
        } else {
            item.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_GREEN));
        }
        item.setData(CAR_KEY, car);
        return item;
    }

    private TableEditor createTableEditor() {
        final TableEditor tableEditor = new TableEditor(this.table);
        tableEditor.grabHorizontal = true;
        return tableEditor;
    }

    private static String[] getAttributesFromCar(final Car car) {
        return new String[]{car.getModel(), car.getPrice(), car.getYear(), car.getEngineKPP(), car.getType(), car.getDistance(),
                car.getPhoto(), car.getCarcase(), car.getColor(), car.getCity(), SDF.format(car.getDate())};
    }

    private static Table createTable(final Composite parent) {
        final Composite composite = new Composite(parent, SWT.NONE);

        final Table table = new Table(composite, SWT.VIRTUAL | SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION | SWT.WRAP);
        //final Table table = new Table(composite, SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION);
        table.setHeaderVisible(true);
        table.setLinesVisible(true);

        final TableColumn[] tableColumns = new TableColumn[columns.length];
        for (int i = 0; i < tableColumns.length; i++) {
            tableColumns[i] = new TableColumn(table, SWT.WRAP);
            tableColumns[i].setText(columns[i]);
        }

        composite.addControlListener(new ResizeColumns(composite, table, tableColumns));

        composite.setLayoutData(new GridData(GridData.FILL_BOTH));
        return table;
    }

    private static class ResizeColumns extends ControlAdapter {
        private final Composite composite;
        private final Table table;
        private final TableColumn[] columns;

        private ResizeColumns(final Composite composite, final Table table, final TableColumn[] columns) {
            this.composite = composite;
            this.table = table;
            this.columns = columns;
        }

        @Override
        public void controlResized(ControlEvent e) {
            final Rectangle area = composite.getClientArea();
            final Point preferredSize = table.computeSize(SWT.DEFAULT, SWT.DEFAULT);
            int width = area.width - 2 * table.getBorderWidth();
            if (preferredSize.y > area.height + table.getHeaderHeight()) {

                // Subtract the scrollbar width from the total column width
                // if a vertical scrollbar will be required
                final Point vBarSize = table.getVerticalBar().getSize();
                width -= vBarSize.x;
            }
            final Point oldSize = table.getSize();
            final int columnWidth = width / (columns.length);
            if (oldSize.x > area.width) {

                // table is getting smaller so make the columns
                // smaller first and then resize the table to
                // match the client area width
                for (final TableColumn column : columns) {
                    column.setWidth(columnWidth);
                }
                table.setSize(area.width, area.height);
            } else {

                // table is getting bigger so make the table
                // bigger first and then make the columns wider
                // to match the client area width
                table.setSize(area.width, area.height);
                for (final TableColumn column : columns) {
                    column.setWidth(columnWidth);
                }
            }
        }
    }
}
